package com.icongyou.enterprise.talent_marking.service.impl;

import com.icongyou.enterprise.common.result.Result;
import com.icongyou.enterprise.talent_marking.entity.dto.MarkPotential;
import com.icongyou.enterprise.talent_marking.entity.vo.HighPotentialSubmissions;
import com.icongyou.enterprise.talent_marking.entity.vo.SubmissionInfo;
import com.icongyou.enterprise.talent_marking.mapper.HighPotentialSubmissionMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
@DisplayName("高潜力成果服务测试")
class HighPotentialSubmissionServiceImplTest {

    @Mock
    private HighPotentialSubmissionMapper potentialSubmissionMapper;

    @InjectMocks
    private HighPotentialSubmissionServiceImpl highPotentialSubmissionService;

    private String userId;
    private String studentId;
    private String submissionId;
    private MarkPotential markPotential;

    @BeforeEach
    void setUp() {
        userId = "USER001";
        studentId = "STUDENT001";
        submissionId = "SUBMISSION001";

        markPotential = new MarkPotential();
        markPotential.setUserId(userId);
        markPotential.setStudentId(studentId);
        markPotential.setSubmissionId(submissionId);
        markPotential.setRemark("优秀作品");
    }

    // ==================== markHighPotential 测试 ====================

    @Test
    @DisplayName("标记高潜力成果 - 成功")
    void testMarkHighPotential_Success() {
        // Arrange
        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId)).thenReturn(null);
        doNothing().when(potentialSubmissionMapper).insert(any(HighPotentialSubmissions.class));

        // Act
        Result result = highPotentialSubmissionService.markHighPotential(markPotential);

        // Assert
        assertEquals(200, result.getCode());
        assertNotNull(result.getData());
        assertTrue(result.getData() instanceof HighPotentialSubmissions);

        HighPotentialSubmissions mark = (HighPotentialSubmissions) result.getData();
        assertEquals(userId, mark.getUserId());
        assertEquals(studentId, mark.getStudentId());
        assertEquals(submissionId, mark.getSubmissionId());
        assertEquals("优秀作品", mark.getRemark());
        assertNotNull(mark.getId());
        assertNotNull(mark.getMarkedTime());

        verify(potentialSubmissionMapper).selectByUserAndSubmission(userId, submissionId);
        verify(potentialSubmissionMapper).insert(any(HighPotentialSubmissions.class));
    }

    @Test
    @DisplayName("标记高潜力成果 - 已存在标记")
    void testMarkHighPotential_AlreadyMarked() {
        // Arrange
        HighPotentialSubmissions existingMark = new HighPotentialSubmissions();
        existingMark.setId("MARK001");
        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId))
                .thenReturn(existingMark);

        // Act
        Result result = highPotentialSubmissionService.markHighPotential(markPotential);

        // Assert
        assertEquals(401, result.getCode());
        assertEquals("该成果已被标记为高潜力", result.getMessage());

        verify(potentialSubmissionMapper).selectByUserAndSubmission(userId, submissionId);
        verify(potentialSubmissionMapper, never()).insert(any());
    }

    @Test
    @DisplayName("标记高潜力成果 - userId为空")
    void testMarkHighPotential_EmptyUserId() {
        // Arrange
        markPotential.setUserId("");

        // Act & Assert
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> highPotentialSubmissionService.markHighPotential(markPotential));
        assertEquals("用户ID、学生ID和提交ID不能为空", exception.getMessage());

        verify(potentialSubmissionMapper, never()).selectByUserAndSubmission(anyString(), anyString());
    }

    @Test
    @DisplayName("标记高潜力成果 - studentId为空")
    void testMarkHighPotential_EmptyStudentId() {
        // Arrange
        markPotential.setStudentId("");

        // Act & Assert
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> highPotentialSubmissionService.markHighPotential(markPotential));
        assertEquals("用户ID、学生ID和提交ID不能为空", exception.getMessage());
    }

    @Test
    @DisplayName("标记高潜力成果 - submissionId为空")
    void testMarkHighPotential_EmptySubmissionId() {
        // Arrange
        markPotential.setSubmissionId("");

        // Act & Assert
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> highPotentialSubmissionService.markHighPotential(markPotential));
        assertEquals("用户ID、学生ID和提交ID不能为空", exception.getMessage());
    }

    @Test
    @DisplayName("标记高潜力成果 - userId为null")
    void testMarkHighPotential_NullUserId() {
        // Arrange
        markPotential.setUserId(null);

        // Act & Assert
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> highPotentialSubmissionService.markHighPotential(markPotential));
        assertEquals("用户ID、学生ID和提交ID不能为空", exception.getMessage());
    }

    @Test
    @DisplayName("标记高潜力成果 - 无备注")
    void testMarkHighPotential_NoRemark() {
        // Arrange
        markPotential.setRemark(null);
        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId)).thenReturn(null);
        doNothing().when(potentialSubmissionMapper).insert(any(HighPotentialSubmissions.class));

        // Act
        Result result = highPotentialSubmissionService.markHighPotential(markPotential);

        // Assert
        assertEquals(200, result.getCode());
        HighPotentialSubmissions mark = (HighPotentialSubmissions) result.getData();
        assertNull(mark.getRemark());
    }

    // ==================== updateRemark 测试 ====================

    @Test
    @DisplayName("更新备注 - 成功")
    void testUpdateRemark_Success() {
        // Arrange
        HighPotentialSubmissions existingMark = new HighPotentialSubmissions();
        existingMark.setId("MARK001");
        existingMark.setUserId(userId);
        existingMark.setSubmissionId(submissionId);
        existingMark.setRemark("旧备注");

        markPotential.setRemark("新备注");

        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId))
                .thenReturn(existingMark);
        doNothing().when(potentialSubmissionMapper).updateById(any(HighPotentialSubmissions.class));

        // Act
        Result result = highPotentialSubmissionService.updateRemark(markPotential);

        // Assert
        assertEquals(200, result.getCode());
        HighPotentialSubmissions updatedMark = (HighPotentialSubmissions) result.getData();
        assertEquals("新备注", updatedMark.getRemark());

        verify(potentialSubmissionMapper).selectByUserAndSubmission(userId, submissionId);
        verify(potentialSubmissionMapper).updateById(existingMark);
    }

    @Test
    @DisplayName("更新备注 - 标记不存在")
    void testUpdateRemark_MarkNotFound() {
        // Arrange
        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId)).thenReturn(null);

        // Act
        Result result = highPotentialSubmissionService.updateRemark(markPotential);

        // Assert
        assertEquals(401, result.getCode());
        assertEquals("未找到对应的高潜力标记记录", result.getMessage());

        verify(potentialSubmissionMapper).selectByUserAndSubmission(userId, submissionId);
        verify(potentialSubmissionMapper, never()).updateById(any());
    }

    @Test
    @DisplayName("更新备注 - 备注为空")
    void testUpdateRemark_EmptyRemark() {
        // Arrange
        HighPotentialSubmissions existingMark = new HighPotentialSubmissions();
        existingMark.setId("MARK001");
        existingMark.setRemark("旧备注");

        markPotential.setRemark("");

        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId))
                .thenReturn(existingMark);
        doNothing().when(potentialSubmissionMapper).updateById(any(HighPotentialSubmissions.class));

        // Act
        Result result = highPotentialSubmissionService.updateRemark(markPotential);

        // Assert
        assertEquals(200, result.getCode());
        HighPotentialSubmissions updatedMark = (HighPotentialSubmissions) result.getData();
        assertEquals("", updatedMark.getRemark());
    }

    // ==================== unmarkHighPotential 测试 ====================

    @Test
    @DisplayName("取消标记 - 成功")
    void testUnmarkHighPotential_Success() {
        // Arrange
        doNothing().when(potentialSubmissionMapper).deleteByUserAndSubmission(userId, submissionId);

        // Act
        Result result = highPotentialSubmissionService.unmarkHighPotential(markPotential);

        // Assert
        assertEquals(200, result.getCode());
        verify(potentialSubmissionMapper).deleteByUserAndSubmission(userId, submissionId);
    }

    @Test
    @DisplayName("取消标记 - 即使记录不存在也成功")
    void testUnmarkHighPotential_RecordNotExists() {
        // Arrange
        doNothing().when(potentialSubmissionMapper).deleteByUserAndSubmission(userId, submissionId);

        // Act
        Result result = highPotentialSubmissionService.unmarkHighPotential(markPotential);

        // Assert
        assertEquals(200, result.getCode());
        verify(potentialSubmissionMapper).deleteByUserAndSubmission(userId, submissionId);
    }

    // ==================== getMyPotentialMarks 测试 ====================

    @Test
    @DisplayName("获取我的标记列表 - 有数据")
    void testGetMyPotentialMarks_WithData() {
        // Arrange
        HighPotentialSubmissions mark1 = new HighPotentialSubmissions();
        mark1.setId("MARK001");
        mark1.setUserId(userId);
        mark1.setStudentId("STUDENT001");
        mark1.setSubmissionId("SUBMISSION001");

        HighPotentialSubmissions mark2 = new HighPotentialSubmissions();
        mark2.setId("MARK002");
        mark2.setUserId(userId);
        mark2.setStudentId("STUDENT002");
        mark2.setSubmissionId("SUBMISSION002");

        List<HighPotentialSubmissions> marks = Arrays.asList(mark1, mark2);
        when(potentialSubmissionMapper.selectByUserId(userId)).thenReturn(marks);

        // Act
        Result result = highPotentialSubmissionService.getMyPotentialMarks(userId);

        // Assert
        assertEquals(200, result.getCode());
        assertNotNull(result.getData());
        @SuppressWarnings("unchecked")
        List<HighPotentialSubmissions> resultList = (List<HighPotentialSubmissions>) result.getData();
        assertEquals(2, resultList.size());

        verify(potentialSubmissionMapper).selectByUserId(userId);
    }

    @Test
    @DisplayName("获取我的标记列表 - 空列表")
    void testGetMyPotentialMarks_EmptyList() {
        // Arrange
        when(potentialSubmissionMapper.selectByUserId(userId)).thenReturn(Collections.emptyList());

        // Act
        Result result = highPotentialSubmissionService.getMyPotentialMarks(userId);

        // Assert
        assertEquals(200, result.getCode());
        assertEquals("暂无高潜力成果标记", result.getMessage());
        assertNotNull(result.getData());

        verify(potentialSubmissionMapper).selectByUserId(userId);
    }

    @Test
    @DisplayName("获取我的标记列表 - null返回")
    void testGetMyPotentialMarks_NullReturn() {
        // Arrange
        when(potentialSubmissionMapper.selectByUserId(userId)).thenReturn(null);

        // Act
        Result result = highPotentialSubmissionService.getMyPotentialMarks(userId);

        // Assert
        assertEquals(200, result.getCode());
        assertEquals("暂无高潜力成果标记", result.getMessage());
    }

    // ==================== getHighPotentialSubmissionInfo 测试 ====================

    @Test
    @DisplayName("获取高潜力成果信息 - 有数据")
    void testGetHighPotentialSubmissionInfo_WithData() {
        // Arrange
        SubmissionInfo info1 = new SubmissionInfo();
        info1.setSubmissionId("SUBMISSION001");
        info1.setStudentName("张三");

        SubmissionInfo info2 = new SubmissionInfo();
        info2.setSubmissionId("SUBMISSION002");
        info2.setStudentName("李四");

        List<SubmissionInfo> infos = Arrays.asList(info1, info2);
        when(potentialSubmissionMapper.selectSubmissionInfoByUserId(userId)).thenReturn(infos);

        // Act
        Result result = highPotentialSubmissionService.getHighPotentialSubmissionInfo(userId);

        // Assert
        assertEquals(200, result.getCode());
        assertNotNull(result.getData());
        @SuppressWarnings("unchecked")
        List<SubmissionInfo> resultList = (List<SubmissionInfo>) result.getData();
        assertEquals(2, resultList.size());

        verify(potentialSubmissionMapper).selectSubmissionInfoByUserId(userId);
    }

    @Test
    @DisplayName("获取高潜力成果信息 - 空列表")
    void testGetHighPotentialSubmissionInfo_EmptyList() {
        // Arrange
        when(potentialSubmissionMapper.selectSubmissionInfoByUserId(userId)).thenReturn(Collections.emptyList());

        // Act
        Result result = highPotentialSubmissionService.getHighPotentialSubmissionInfo(userId);

        // Assert
        assertEquals(200, result.getCode());
        assertEquals("暂无高潜力成果", result.getMessage());

        verify(potentialSubmissionMapper).selectSubmissionInfoByUserId(userId);
    }

    @Test
    @DisplayName("获取高潜力成果信息 - null返回")
    void testGetHighPotentialSubmissionInfo_NullReturn() {
        // Arrange
        when(potentialSubmissionMapper.selectSubmissionInfoByUserId(userId)).thenReturn(null);

        // Act
        Result result = highPotentialSubmissionService.getHighPotentialSubmissionInfo(userId);

        // Assert
        assertEquals(200, result.getCode());
        assertEquals("暂无高潜力成果", result.getMessage());
    }

    // ==================== isSubmissionMarked 测试 ====================

    @Test
    @DisplayName("检查是否已标记 - 已标记")
    void testIsSubmissionMarked_AlreadyMarked() {
        // Arrange
        HighPotentialSubmissions existingMark = new HighPotentialSubmissions();
        existingMark.setId("MARK001");
        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId))
                .thenReturn(existingMark);

        // Act
        boolean result = highPotentialSubmissionService.isSubmissionMarked(userId, submissionId);

        // Assert
        assertTrue(result);
        verify(potentialSubmissionMapper).selectByUserAndSubmission(userId, submissionId);
    }

    @Test
    @DisplayName("检查是否已标记 - 未标记")
    void testIsSubmissionMarked_NotMarked() {
        // Arrange
        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId)).thenReturn(null);

        // Act
        boolean result = highPotentialSubmissionService.isSubmissionMarked(userId, submissionId);

        // Assert
        assertFalse(result);
        verify(potentialSubmissionMapper).selectByUserAndSubmission(userId, submissionId);
    }

    // ==================== 边界条件测试 ====================

    @Test
    @DisplayName("标记高潜力成果 - 验证UUID生成")
    void testMarkHighPotential_UUIDGeneration() {
        // Arrange
        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId)).thenReturn(null);

        ArgumentCaptor<HighPotentialSubmissions> captor = ArgumentCaptor.forClass(HighPotentialSubmissions.class);
        doNothing().when(potentialSubmissionMapper).insert(captor.capture());

        // Act
        highPotentialSubmissionService.markHighPotential(markPotential);

        // Assert
        HighPotentialSubmissions captured = captor.getValue();
        assertNotNull(captured.getId());
        assertTrue(captured.getId().length() > 0);
    }

    @Test
    @DisplayName("标记高潜力成果 - 验证时间戳")
    void testMarkHighPotential_TimestampGeneration() {
        // Arrange
        when(potentialSubmissionMapper.selectByUserAndSubmission(userId, submissionId)).thenReturn(null);

        ArgumentCaptor<HighPotentialSubmissions> captor = ArgumentCaptor.forClass(HighPotentialSubmissions.class);
        doNothing().when(potentialSubmissionMapper).insert(captor.capture());

        Date beforeCall = new Date();

        // Act
        highPotentialSubmissionService.markHighPotential(markPotential);

        Date afterCall = new Date();

        // Assert
        HighPotentialSubmissions captured = captor.getValue();
        assertNotNull(captured.getMarkedTime());
        assertTrue(captured.getMarkedTime().getTime() >= beforeCall.getTime());
        assertTrue(captured.getMarkedTime().getTime() <= afterCall.getTime());
    }
}
